<!DOCTYPE html><html lang="zh-Hans"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"><meta name="description" content="vue3视频简单记录"><meta name="keywords" content="vue3"><meta name="author" content="晟松"><meta name="copyright" content="晟松"><title>vue3视频简单记录 | 晟松</title><link rel="shortcut icon" href="/logo.png"><link rel="stylesheet" href="/css/index.css?version=1.9.0"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@latest/css/font-awesome.min.css?version=1.9.0"><meta name="format-detection" content="telephone=no"><meta http-equiv="x-dns-prefetch-control" content="on"><link rel="dns-prefetch" href="https://cdn.jsdelivr.net"><link rel="dns-prefetch" href="https://hm.baidu.com"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?c34d81d53341febe06a155941e2df16d";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();</script><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><script>var GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"search.xml","languages":{"hits_empty":"找不到您查询的内容:${query}"}},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  hexoVersion: '5.4.0'
} </script><meta name="generator" content="Hexo 5.4.0"></head><body><i class="fa fa-arrow-right" id="toggle-sidebar" aria-hidden="true"></i><div id="sidebar" data-display="true"><div class="toggle-sidebar-info text-center"><span data-toggle="切换文章详情">切换站点概览</span><hr></div><div class="sidebar-toc"><div class="sidebar-toc__title">目录</div><div class="sidebar-toc__progress"><span class="progress-notice">你已经读了</span><span class="progress-num">0</span><span class="progress-percentage">%</span><div class="sidebar-toc__progress-bar"></div></div><div class="sidebar-toc__content"><ol class="toc"><li class="toc-item toc-level-4"><a class="toc-link" href="#vue3-diff%E7%AE%97%E6%B3%95%E4%BC%98%E5%8C%96"><span class="toc-number">1.</span> <span class="toc-text">vue3 diff算法优化</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#vue3%E7%BB%84%E5%90%88%E5%BC%8Fapi%E4%BD%BF%E7%94%A8"><span class="toc-number">2.</span> <span class="toc-text">vue3组合式api使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BB%84%E5%90%88api%E6%9C%AC%E8%B4%A8"><span class="toc-number">3.</span> <span class="toc-text">组合api本质</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#reactive%E5%92%8Cref"><span class="toc-number">4.</span> <span class="toc-text">reactive和ref</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#reactive"><span class="toc-number">4.1.</span> <span class="toc-text">reactive</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#ref"><span class="toc-number">4.2.</span> <span class="toc-text">ref</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%B8%A4%E8%80%85%E5%8C%BA%E5%88%AB"><span class="toc-number">4.3.</span> <span class="toc-text">两者区别</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%80%92%E5%BD%92%E7%9B%91%E5%90%AC"><span class="toc-number">5.</span> <span class="toc-text">递归监听</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%9D%9E%E9%80%92%E5%BD%92%E7%9B%91%E5%90%AC"><span class="toc-number">6.</span> <span class="toc-text">非递归监听</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89hook%E5%87%BD%E6%95%B0"><span class="toc-number">7.</span> <span class="toc-text">自定义hook函数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#toRaw"><span class="toc-number">8.</span> <span class="toc-text">toRaw</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#markRaw"><span class="toc-number">9.</span> <span class="toc-text">markRaw</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#toRef"><span class="toc-number">10.</span> <span class="toc-text">toRef</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#toRefs"><span class="toc-number">11.</span> <span class="toc-text">toRefs</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#customRef"><span class="toc-number">12.</span> <span class="toc-text">customRef</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#dom-ref"><span class="toc-number">13.</span> <span class="toc-text">dom-ref</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#readonly"><span class="toc-number">14.</span> <span class="toc-text">readonly</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#watchEffect"><span class="toc-number">15.</span> <span class="toc-text">watchEffect</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#watch"><span class="toc-number">16.</span> <span class="toc-text">watch</span></a></li></ol></div></div><div class="author-info hide"><div class="author-info__avatar text-center"><img src="/img/avatar.png"></div><div class="author-info__name text-center">晟松</div><div class="author-info__description text-center">晟松的博客</div><div class="follow-button"><a target="_blank" rel="noopener" href="https://gitee.com/cheng_song">Gitee</a></div><hr><div class="author-info-articles"><a class="author-info-articles__archives article-meta" href="/archives"><span class="pull-left">文章</span><span class="pull-right">52</span></a><a class="author-info-articles__tags article-meta" href="/tags"><span class="pull-left">标签</span><span class="pull-right">45</span></a></div></div></div><div id="content-outer"><div id="top-container" style="background-image: url(/img/blog-bg.jpg)"><div id="page-header"><span class="pull-left"> <a id="site-name" href="/">晟松</a></span><i class="fa fa-bars toggle-menu pull-right" aria-hidden="true"></i><span class="pull-right menus">   <a class="site-page" href="/">Home</a><a class="site-page" href="/archives">Archives</a><a class="site-page" href="/tags">Tags</a><a class="site-page" href="/categories">Categories</a></span><span class="pull-right"><a class="site-page social-icon search"><i class="fa fa-search"></i><span> 搜索</span></a></span></div><div id="post-info"><div id="post-title">vue3视频简单记录</div><div id="post-meta"><time class="post-meta__date"><i class="fa fa-calendar" aria-hidden="true"></i> 2021-02-15</time><div class="post-meta-wordcount"><span>字数总计: </span><span class="word-count">2.7k</span><span class="post-meta__separator">|</span><span>阅读时长: 9 分钟</span></div></div></div></div><div class="layout" id="content-inner"><article id="post"><div class="article-container" id="post-content"><p>就是对一个vue3的教程视频的简单记录</p>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV14k4y117LL?p=1">B站视频地址</a></p>
<h4 id="vue3-diff算法优化"><a href="#vue3-diff算法优化" class="headerlink" title="vue3 diff算法优化"></a>vue3 diff算法优化</h4><p>vue3新增对节点进行patchFlag，当与上次虚拟节点对比的时候，只需要对比带有patchFlag的节点</p>
<p>还有一些其他的优化方面</p>
<p>里面的那一个网址是vue3 Template explore的网址</p>
<img src="https://gitee.com/cheng_song/picgo-img/raw/master/img/image-20210215111309144.png" alt="image-20210215111309144" style="zoom:80%;" />





<h4 id="vue3组合式api使用"><a href="#vue3组合式api使用" class="headerlink" title="vue3组合式api使用"></a>vue3组合式api使用</h4><p>1.直接在setup里面将所有的逻辑都写在里面，很垃圾</p>
<p>2.将同一个逻辑所需的数据，方法都写在一个函数里面，并都return出来，然后在setup里面调用这个函数并解构出前面return出的数据、方法。最后统一在setup里面再return出来，之前的一个博客 <a href="https://chengsong.info/2020/10/29/vue3%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8/#toc-heading-4">vue3简单使用</a> 里面的最后面有简单记录</p>
<p>3.类似于2所说，但同一个逻辑的所有数据方法都写在一个外部的js文件里面（记得导入那些需要的组合式api），并使用export default xxx 导出，然后在需要的.vue文件里面使用import导入，然后在setup里面使用，其他的就跟2差不多。这样做主要是更好的具有维护性和扩展性</p>
<p><strong>记住composition api 和 option api 是可以混在一起使用的</strong> </p>
<p>比如 可使用 <strong>data</strong> 定义一些响应式数据，也可以使用ref和reactive定义响应式数据</p>
<p><strong>setup函数是在 beforeCreate钩子之前执行的</strong> ，所以在setup里面不能访问vue2的<strong>this</strong></p>
<p>setup函数必须是同步的，不能是异步的，即不能在setup的前面加上 <strong>async</strong>，可以在里面调用函数的时候，将那些函数变成异步的</p>
<h4 id="组合api本质"><a href="#组合api本质" class="headerlink" title="组合api本质"></a>组合api本质</h4><p>可以将这个当做一个 <strong>注入</strong> 的过程，你在setup里面return出去的数据和方法，都会被注入到原来的option api里面，该是data里面的就注入到data里面，该是methods里面的，就注入到methods里面 …… </p>
<h4 id="reactive和ref"><a href="#reactive和ref" class="headerlink" title="reactive和ref"></a>reactive和ref</h4><h5 id="reactive"><a href="#reactive" class="headerlink" title="reactive"></a>reactive</h5><p>vue3使用proxy实现响应式数据    reactive的参数必须是一个自定义的对象或数组，不能是其他的对象，比如说通过 new Data() 创建出一个时间对象参数，默认情况下，修改这个对象，界面不会自动刷新，只能通过重新赋值的方式属性</p>
<p>可在return的时候通过 <strong>toRefs</strong> api将对象中的每一个属性都转为ref形式</p>
<h5 id="ref"><a href="#ref" class="headerlink" title="ref"></a>ref</h5><p>一般使用来对简单值的监听，比如number、string这些，在js里面访问的时候需要使用 .value访问，在template里面不需要，因为vue会自动添加.value</p>
<p>ref的本质还是reactive，当我们给ref传一个值的时候，ref底层会在会自动将ref转为reactive，所以需要 .value进行访问和修改</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">ref(18)  -&gt;	 reactive(&#123;value:18&#125;)</span><br></pre></td></tr></table></figure>

<h5 id="两者区别"><a href="#两者区别" class="headerlink" title="两者区别"></a>两者区别</h5><p>其实将ref出来的数据和reactive出来的数据简单console一下就会发现这两者其实不同，在ref创建出的数据里面会有一个 <strong>__v_isRef</strong> 的属性进行判断是否为ref，在template里面就是vue通过这个来判断是否添加 .value </p>
<p>在composition api里面还有 isRef和isRactive两个api判断数据的所属</p>
<h4 id="递归监听"><a href="#递归监听" class="headerlink" title="递归监听"></a>递归监听</h4><p>默认ref和reactive创造出来的数据都是递归监听（即对象里面包含对象（引用值），里面的对象修改之后也能被监听）</p>
<p>但递归监听当数据量非常大的时候就会非常消耗性能，因为vue3为了能实现响应式监听，会递归将里面的每一层都包装成proxy对象来实现响应式监听</p>
<h4 id="非递归监听"><a href="#非递归监听" class="headerlink" title="非递归监听"></a>非递归监听</h4><p>就是只监听第一层，不监听下面的层，即下面的层不会被包装成proxy对象，当下面的对象被修改，而第一层的属性没有修改，就不会触发响应式来修改ui，重新渲染(<strong>记住</strong>，如果第一层的属性被修改了，而下面层的属性也改变了，因为第一层的修改触发ui的修改，所以下面层的修改也会被体现到ui上面来，而不是保持原来的ui渲染不变) </p>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV14k4y117LL?p=16&spm_id_from=pageDriver">具体看这个视频</a></p>
<p>主要是通过两个api    <strong>shallowReactive</strong> <strong>shallowRef</strong>     用法跟ref和reactive一样 主要用于数据量比较大的时候才使用</p>
<p>注意使用<strong>shallowRef</strong> 的时候，vue监听的是.value的变化，并不是第一层的数据变化，所以可以</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> state = shallowRef(&#123;</span><br><span class="line">	<span class="attr">a</span>:<span class="number">1</span>,</span><br><span class="line">	<span class="attr">b</span>:&#123;<span class="attr">c</span>:<span class="number">2</span>,</span><br><span class="line">       <span class="attr">d</span>:&#123;</span><br><span class="line">		<span class="attr">e</span>:<span class="number">3</span></span><br><span class="line">	&#125;&#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">state.value.a = <span class="number">21</span>	<span class="comment">// 这样的修改不会触发响应式</span></span><br><span class="line">state.value = &#123;<span class="attr">a</span>:<span class="number">21</span>,<span class="attr">b</span>:&#123;&#125;&#125; <span class="comment">// 这样的才会</span></span><br></pre></td></tr></table></figure>

<p>shallowRef 本质上还是调用了shallowRactive</p>
<p>此外还有一个 <strong>triggerRef</strong> 的api根据传入的数据主动的更新界面</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">state.value.b.c = 22</span><br><span class="line">triggerRef(state) // 使用方式</span><br></pre></td></tr></table></figure>

<p>注意没有提供 triggerRactive 这个api</p>
<h4 id="自定义hook函数"><a href="#自定义hook函数" class="headerlink" title="自定义hook函数"></a>自定义hook函数</h4><ul>
<li>使用Vue3的组合API封装的可复用的功能函数</li>
<li>自定义hook的作用类似于vue2中的mixin技术</li>
<li>自定义Hook的优势: 很清楚复用功能代码的来源, 更清楚易懂</li>
</ul>
<h4 id="toRaw"><a href="#toRaw" class="headerlink" title="toRaw"></a>toRaw</h4><p>官网说法：返回由 <code>reactive</code> 或 <code>readonly</code> 方法转换成响应式代理的普通对象。这是一个还原方法，可用于临时读取，访问不会被代理/跟踪，写入时也不会触发更改</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> foo = &#123;<span class="attr">a</span>:<span class="number">12</span>&#125;</span><br><span class="line"><span class="keyword">const</span> reactiveFoo = reactive(foo)</span><br><span class="line"><span class="comment">// reactiveFoo本质上是一个proxy对象，在这个proxy对象引用了foo对象</span></span><br><span class="line"><span class="built_in">console</span>.log(toRaw(reactiveFoo) === foo) <span class="comment">// true</span></span><br><span class="line"><span class="comment">// 注意使用ref的话，需要使用	toRaw(reactiveFoo.value)</span></span><br></pre></td></tr></table></figure>

<p>如果这里通过reactiveFoo修改里面的属性，会响应式的变化，但当通过foo修改属性的时候，虽然reactiveFoo的proxy对象里面的数据发生了变化，但界面不会发生变化</p>
<p>ref/reactive数据类型的特点:<br>每次修改都会被追踪，都会更新UI界面，但是这样其实是非常消耗性能的所以如果我们有一些操作不需要追踪，不需要更新UI界面，那么这个时候，我们就可以通过toRaw方法拿到它的原始数据，对原始数据进行修改，这样就不会被追踪,这样就不会更新UI界面，这样性能就优化了</p>
<h4 id="markRaw"><a href="#markRaw" class="headerlink" title="markRaw"></a>markRaw</h4><p>显式标记一个对象为“永远不会转为响应式代理”，函数返回这个对象本身。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> foo = markRaw(&#123;&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(isReactive(reactive(foo))) <span class="comment">// false</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果被 markRaw 标记了，即使在响应式对象中作属性，也依然不是响应式的</span></span><br><span class="line"><span class="keyword">const</span> bar = reactive(&#123; foo &#125;)</span><br><span class="line"><span class="built_in">console</span>.log(isReactive(bar.foo)) <span class="comment">// false</span></span><br></pre></td></tr></table></figure>

<h4 id="toRef"><a href="#toRef" class="headerlink" title="toRef"></a>toRef</h4><p><code>toRef</code> 可以用来为一个 reactive 对象的属性创建一个 ref。这个 ref 可以被传递并且能够保持响应性。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> state = reactive(&#123;</span><br><span class="line">  <span class="attr">foo</span>: <span class="number">1</span>,</span><br><span class="line">  <span class="attr">bar</span>: <span class="number">2</span>,</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> fooRef = toRef(state, <span class="string">&#x27;foo&#x27;</span>)</span><br><span class="line"></span><br><span class="line">fooRef.value++</span><br><span class="line"><span class="built_in">console</span>.log(state.foo) <span class="comment">// 2</span></span><br><span class="line"></span><br><span class="line">state.foo++</span><br><span class="line"><span class="built_in">console</span>.log(fooRef.value) <span class="comment">// 3</span></span><br></pre></td></tr></table></figure>

<p>当您要将一个 prop 中的属性作为 ref 传给组合逻辑函数时，<code>toRef</code> 就派上了用场：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="function"><span class="title">setup</span>(<span class="params">props</span>)</span> &#123;</span><br><span class="line">    useSomeFeature(toRef(props, <span class="string">&#x27;foo&#x27;</span>))</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="toRefs"><a href="#toRefs" class="headerlink" title="toRefs"></a>toRefs</h4><p>把一个响应式对象转换成普通对象，该普通对象的每个 property 都是一个 ref ，和响应式对象 property 一一对应。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> state = reactive(&#123;</span><br><span class="line">  <span class="attr">foo</span>: <span class="number">1</span>,</span><br><span class="line">  <span class="attr">bar</span>: <span class="number">2</span>,</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> stateAsRefs = toRefs(state)</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">stateAsRefs 的类型如下:</span></span><br><span class="line"><span class="comment">&#123;</span></span><br><span class="line"><span class="comment">  foo: Ref&lt;number&gt;,</span></span><br><span class="line"><span class="comment">  bar: Ref&lt;number&gt;</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// ref 对象 与 原属性的引用是 &quot;链接&quot; 上的</span></span><br><span class="line">state.foo++</span><br><span class="line"><span class="built_in">console</span>.log(stateAsRefs.foo) <span class="comment">// 2</span></span><br><span class="line"><span class="comment">// 注意下面 .value的位置</span></span><br><span class="line">stateAsRefs.foo.value++</span><br><span class="line"><span class="built_in">console</span>.log(state.foo) <span class="comment">// 3</span></span><br></pre></td></tr></table></figure>

<p>当想要从一个组合逻辑函数中返回响应式对象时，用 <code>toRefs</code> 是很有效的，该 API 让消费组件可以 解构 / 扩展（使用 <code>...</code> 操作符）返回的对象，并不会丢失响应性：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">useFeatureX</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> state = reactive(&#123;</span><br><span class="line">    <span class="attr">foo</span>: <span class="number">1</span>,</span><br><span class="line">    <span class="attr">bar</span>: <span class="number">2</span>,</span><br><span class="line">  &#125;)</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 对 state 的逻辑操作</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// 返回时将属性都转为 ref</span></span><br><span class="line">  <span class="keyword">return</span> toRefs(state)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="function"><span class="title">setup</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="comment">// 可以解构，不会丢失响应性</span></span><br><span class="line">    <span class="keyword">const</span> &#123; foo, bar &#125; = useFeatureX()</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      foo,</span><br><span class="line">      bar,</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="customRef"><a href="#customRef" class="headerlink" title="customRef"></a>customRef</h4><p><code>customRef</code> 用于自定义一个 <code>ref</code>，可以显式地控制依赖追踪和触发响应，接受一个工厂函数，两个参数分别是用于追踪的 <code>track</code> 与用于触发响应的 <code>trigger</code>，并返回一个一个带有 <code>get</code> 和 <code>set</code> 属性的对象</p>
<p>在get里面不能发送网络请求，因为请求到数据之后，界面就要刷新，刷新就会又调用get，然后又会刷新，然后无限循环；可以在return的前面发送网络请求，这样就不会循环发送请求</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">myRef</span>(<span class="params">value, delay = <span class="number">200</span></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> timeout</span><br><span class="line">  <span class="comment">// 这里接收一个回调函数，同时track和trigger是实现响应式的关键</span></span><br><span class="line">  <span class="keyword">return</span> customRef(<span class="function">(<span class="params">track, trigger</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="function"><span class="title">get</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        track() <span class="comment">// 告诉vue需要追踪这个值</span></span><br><span class="line">        <span class="keyword">return</span> value</span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="function"><span class="title">set</span>(<span class="params">newValue</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">clearTimeout</span>(timeout)</span><br><span class="line">        timeout = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">          value = newValue</span><br><span class="line">          trigger() <span class="comment">// 告诉vue触发页面更新，会调用一次上面的get方法</span></span><br><span class="line">        &#125;, delay)</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="function"><span class="title">setup</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">text</span>: myRef(<span class="string">&#x27;hello&#x27;</span>),</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>感觉这个用法虽然高级，但有些麻烦了</p>
<h4 id="dom-ref"><a href="#dom-ref" class="headerlink" title="dom-ref"></a>dom-ref</h4><p>这里的ref是vue2里面的那个控制dom元素的ref，这里只是记录一下用法</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;div ref=<span class="string">&quot;box&quot;</span>&gt; &lt;/div&gt;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">setup</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">	<span class="keyword">let</span> box = ref(<span class="literal">null</span>) <span class="comment">// 这里的box就是上面的box，实际上还是 reactive(&#123;value:null&#125;)</span></span><br><span class="line">	onMounted(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="comment">// 在渲染完成后, 这个 div DOM 会被赋值给 root ref 对象</span></span><br><span class="line">        <span class="built_in">console</span>.log(box.value) <span class="comment">// &lt;div/&gt;</span></span><br><span class="line">        box.value.style.color = <span class="string">&#x27;fff&#x27;</span> <span class="comment">// 使用方式</span></span><br><span class="line">      &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="readonly"><a href="#readonly" class="headerlink" title="readonly"></a>readonly</h4><p>传入一个对象（响应式或普通）或 ref，返回一个原始对象的<strong>只读</strong>代理。一个只读的代理是“深层的”，对象内部任何嵌套的属性也都是只读的。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> original = reactive(&#123; <span class="attr">count</span>: <span class="number">0</span> &#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> copy = readonly(original)</span><br><span class="line"></span><br><span class="line">watchEffect(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 依赖追踪</span></span><br><span class="line">  <span class="built_in">console</span>.log(copy.count)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// original 上的修改会触发 copy 上的侦听</span></span><br><span class="line">original.count++</span><br><span class="line"></span><br><span class="line"><span class="comment">// 无法修改 copy 并会被警告</span></span><br><span class="line">copy.count++ <span class="comment">// warning!</span></span><br></pre></td></tr></table></figure>

<p>注意const和readonly的区别</p>
<p>const: 赋值保护，不能变量重新赋值</p>
<p>readonly: 属性保护，不能属性重新赋值，即对象里面的属性也没法赋值，但const里面的对象属性可以赋值</p>
<p>还有 <code>isReadonly</code> <code>shallowReadonly</code> 这两个api，作用、用法与上面类似，就不记录了</p>
<h4 id="watchEffect"><a href="#watchEffect" class="headerlink" title="watchEffect"></a>watchEffect</h4><p>立即执行传入的一个函数，并响应式追踪其依赖，并在其依赖变更时重新运行该函数。<a href=""></a></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 也可以停止监听</span></span><br><span class="line"><span class="keyword">const</span> stop = watchEffect(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">/* ... */</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 之后</span></span><br><span class="line">stop()</span><br></pre></td></tr></table></figure>



<h4 id="watch"><a href="#watch" class="headerlink" title="watch"></a>watch</h4><p>感觉vue3的watch用法有了一些改变，当观测的数据是reactive的时候，需要传递一个箭头函数，返回这个reactive里面的值</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> state = reactive(&#123; <span class="attr">count</span>: <span class="number">0</span> &#125;)</span><br><span class="line">watch(</span><br><span class="line">  <span class="function">() =&gt;</span> state.count,	<span class="comment">// 这里需要一个箭头函数</span></span><br><span class="line">  <span class="function">(<span class="params">count, prevCount</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">/* ... */</span></span><br><span class="line">  &#125;</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 直接侦听一个ref</span></span><br><span class="line"><span class="keyword">const</span> count = ref(<span class="number">0</span>)</span><br><span class="line">watch(count, <span class="function">(<span class="params">count, prevCount</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">/* ... */</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>





<p>后面的主要是关于一些原理的手写实现，现在就不记录了，等后面除了新的东西再记录吧</p>
</div></article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">晟松</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://chengsong.info/2021/02/15/vue3视频简单记录/">https://chengsong.info/2021/02/15/vue3视频简单记录/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://chengsong.info">晟松</a>！</span></div></div><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/vue3/">vue3</a></div><nav id="pagination"><div class="prev-post pull-left"><a href="/2021/03/08/typescript-vue3%E7%AE%80%E5%8D%95%E5%AD%A6%E4%B9%A0/"><i class="fa fa-chevron-left">  </i><span>typescript+vue3简单学习</span></a></div><div class="next-post pull-right"><a href="/2021/02/06/Nuxt%E8%BF%9B%E4%B8%80%E6%AD%A5%E5%AD%A6%E4%B9%A0/"><span>Nuxt进一步学习</span><i class="fa fa-chevron-right"></i></a></div></nav></div></div><footer class="footer-bg" style="background-image: url(/img/blog-bg.jpg)"><div class="layout" id="footer"><div class="copyright">&copy;2020 - 2023 By 晟松</div><div class="framework-info"><span>驱动 - </span><a target="_blank" rel="noopener" href="http://hexo.io"><span>Hexo</span></a><span class="footer-separator">|</span><span>主题 - </span><a target="_blank" rel="noopener" href="https://github.com/Molunerfinn/hexo-theme-melody"><span>Melody</span></a></div><div class="icp"><a target="_blank" rel="noopener" href="http://www.beian.miit.gov.cn/"><span>湘ICP备2020021729号</span></a></div><div class="busuanzi"><script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><span id="busuanzi_container_page_pv"><i class="fa fa-file"></i><span id="busuanzi_value_page_pv"></span><span></span></span></div></div></footer><i class="fa fa-arrow-up" id="go-up" aria-hidden="true"></i><script src="https://cdn.jsdelivr.net/npm/animejs@latest/anime.min.js"></script><script src="https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@latest/velocity.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-ui-pack@latest/velocity.ui.min.js"></script><script src="/js/utils.js?version=1.9.0"></script><script src="/js/fancybox.js?version=1.9.0"></script><script src="/js/sidebar.js?version=1.9.0"></script><script src="/js/copy.js?version=1.9.0"></script><script src="/js/fireworks.js?version=1.9.0"></script><script src="/js/transition.js?version=1.9.0"></script><script src="/js/scroll.js?version=1.9.0"></script><script src="/js/head.js?version=1.9.0"></script><script src="/js/search/local-search.js"></script><script>if(/Android|webOS|iPhone|iPod|iPad|BlackBerry/i.test(navigator.userAgent)) {
  $('#nav').addClass('is-mobile')
  $('footer').addClass('is-mobile')
  $('#top-container').addClass('is-mobile')
}</script><div class="search-dialog" id="local-search"><div class="search-dialog__title" id="local-search-title">本地搜索</div><div id="local-input-panel"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章"></div></div></div><hr><div id="local-search-results"><div id="local-hits"></div><div id="local-stats"><div class="local-search-stats__hr" id="hr"><span>由</span> <a target="_blank" rel="noopener" href="https://github.com/wzpan/hexo-generator-search" style="color:#49B1F5;">hexo-generator-search</a>
 <span>提供支持</span></div></div></div><span class="search-close-button"><i class="fa fa-times"></i></span></div><div class="search-mask"></div></body></html>